﻿using System.IO;

using Uhi.Libraries.Windows.Models;

namespace Uhi.Applications.FileAid.Model
{
    #region RecordInfo
    /// <summary>
    /// ファイルの 1 行分のデータを表す。
    /// </summary>
    public class RecordInfo : ModelBase, IRecordInfo
    {
        #region _ctor
        /// <summary>
        /// <see cref="RecordInfo"/> の新しいインスタンスを生成する。
        /// </summary>
        /// <param name="filename">ファイル名。</param>
        /// <param name="offset">データの開始位置。</param>
        /// <param name="length">データのレコード長。</param>
        /// <param name="line">データの行番号。</param>
        public RecordInfo(string filename, int offset, int length, int line)
        {
            this.Filename = filename;
            this.Offset = offset;
            this.Length = length;
            this.Line = line;
        }
        #endregion

        #region Filename
        /// <summary>
        /// ファイル名を取得する。
        /// </summary>
        public string Filename { get; private set; }
        #endregion

        #region Offset
        /// <summary>
        /// データの開始位置を取得する。
        /// </summary>
        public int Offset { get; private set; }
        #endregion

        #region Length
        /// <summary>
        /// データのレコード長を取得する。
        /// </summary>
        public int Length { get; private set; }
        #endregion

        #region Line
        /// <summary>
        /// データの行番号を取得する。
        /// </summary>
        /// <remarks>
        /// 先頭の行番号は 0。
        /// </remarks>
        public int Line { get; private set; }
        #endregion

        #region IsEdited
        /// <summary>
        /// データが変更済みかどうかを判定する値を取得、または設定する。
        /// </summary>
        public bool IsEdited { get; set; }
        #endregion

        #region Record

        /// <summary>
        /// このインスタンスが表すレコードのデータ。
        /// </summary>
        private byte[] record;

        /// <summary>
        /// このインスタンスが表すレコードのデータを取得、または設定する。
        /// </summary>
        public byte[] Record
        {
            get
            {
                if (this.record != null)
                    return this.record;

                using (var st = new FileStream(this.Filename, FileMode.Open, FileAccess.Read))
                {
                    this.record = new byte[this.Length];
                    st.Seek(this.Offset, SeekOrigin.Begin);
                    st.Read(this.record, 0, this.Length);
                }

                return this.record;
            }
            set
            {
                this.record = value;
                this.IsEdited = true;
            }
        }

        #endregion

        #region Save

        /// <summary>
        /// <see cref="Record"/> をファイルに書き込む。
        /// </summary>
        public void Save()
        {
            if (!this.IsEdited)
                return;

            this.SaveCore(this.Filename);
        }

        /// <summary>
        /// <see cref="Record"/> を指定したファイルに書き込む。
        /// </summary>
        /// <param name="path">ファイルの path。</param>
        public void SaveAs(string path)
        {
            this.SaveCore(path);
        }

        /// <summary>
        /// <see cref="Record"/> を指定したファイルに書き込む。
        /// </summary>
        /// <param name="path">ファイルの path。</param>
        private void SaveCore(string path)
        {
            using (var st = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
            {
                st.Seek(this.Length * this.Line, SeekOrigin.Begin);
                st.Write(this.Record, 0, this.Record.Length);
            }
        }

        #endregion
    }
    #endregion
}
